#ifndef NOISE_GLSL
#define NOISE_GLSL

//note: normalized random, float=[0;1[
float NRand( vec2 n ) 
{
	return fract( sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453 );
}

vec2 NRand2( vec2 n ) 
{
	return fract( sin(dot(n.xy, vec2(12.9898, 78.233)))* vec2(43758.5453, 28001.8384) );
}

vec3 NRand3( vec2 n ) 
{
	return fract( sin(dot(n.xy, vec2(12.9898, 78.233)))* vec3(43758.5453, 28001.8384, 50849.4141 ) );
}

vec4 NRand4( vec2 n ) 
{
	return fract( sin(dot(n.xy, vec2(12.9898, 78.233)))* vec4(43758.5453, 28001.8384, 50849.4141, 12996.89) );
}

//note: signed random, float=[-1;1[
float SRand( vec2 n ) 
{
	return NRand( n ) * 2.0 - 1.0;
}

vec2 SRand2( vec2 n ) 
{
	return NRand2( n ) * 2.0 - 1.0;
}

vec3 SRand3( vec2 n ) 
{
	return NRand3( n ) * 2.0 - 1.0;
}

vec4 SRand4( vec2 n ) 
{
	return NRand4( n ) * 2.0 - 1.0;
}

//note: sample noise form texture
float SampleBlueNoise(ivec2 coord, int sampleIndex, int sampleDimension, sampler2D sobolSequence, sampler2D scramblingRanking)
{
	// wrap arguments
	coord.x = coord.x % 128;
	coord.y = coord.y % 128;
	sampleIndex = sampleIndex % 256;
	sampleDimension = sampleDimension % 4;

	// xor index based on optimized ranking
	int rankedSampleIndex = sampleIndex ^ int(clamp(texelFetch(scramblingRanking, ivec2(coord.x, coord.y), 0).b * 256.0f, 0.0f, 255.0f));
	
    // fetch value in sequence
	int value = int(clamp(texelFetch(sobolSequence, ivec2(rankedSampleIndex, 0), 0)[sampleDimension] * 256.0f, 0.0f, 255.0f));
	
    // If the dimension is optimized, xor sequence value based on optimized scrambling
	value = value ^ int(clamp(texelFetch(scramblingRanking, ivec2(coord.x, coord.y), 0)[sampleDimension % 2] * 256.0f, 0.0f, 255.0f));
	
    // convert to float and return
	float v = (0.5f + value) / 256.0f;
	return v;
}

#endif